/**
 * Configures a calendar event and sets meta data.
 */
function configureCalendarEvent_(evt, booking) {
  
  // Set event properties
  evt.setGuestsCanModify(false);
  evt.setGuestsCanInviteOthers(false);
  evt.setGuestsCanSeeGuests(false);
  
  // Add additional metadata
  evt.setTag("isFieldBooking", booking.isFieldBooking);
  evt.setTag("isHouseBooking", booking.isHouseBooking);
  evt.setTag("OrgName", booking.organisation.name);
  evt.setTag("OrgType", booking.organisation.type);
  evt.setTag("HeadCount", (booking.participants + booking.leaders));
  evt.setTag("BookingState", "Provisional");
  
  // Show details in calendar
  evt.setVisibility(CalendarApp.Visibility.PUBLIC);
}

/**
 * Creates an event in the calendar.
 * @return the ID of the created event.
 */
function createEvent_(booking) {
  
  var title = "[P] " + booking.organisation.name + " (" + booking.participants + " participants, " + booking.leaders + " leaders)";
  var location = "";
  if(booking.isHouseBooking && !booking.isFieldBooking) {
    location = "Ellesborough House";
  }
  if(!booking.isHouseBooking && booking.isFieldBooking) {
    location = "Ellesborough Field";
  }
  if(booking.isHouseBooking && booking.isFieldBooking) {
    location = "Ellesborough House and Field";
  }
  
  var guestList = booking.contact.email;
  var startTime = booking.arrivalDate;
  var endTime = booking.departureDate;
  
  var options = {
      "location"    : location
    , "guests"      : guestList
    , "sendInvites" : false
  };
  
  // Create entry in details calendar
  // Get calendar and create event
  var cal = CalendarApp.getCalendarById("ellesboroughguidecentre@gmail.com");
  var evt = cal.createEvent(title, startTime, endTime, options);
  
  // Set up event
  configureCalendarEvent_(evt, booking);
  evt.setDescription("Contact: " + booking.contact.name + " - " + booking.contact.telephone);
  evt.setVisibility(CalendarApp.Visibility.PRIVATE);
  evt.setTag("BookingDetails", true);
    
  // Save event ID
  var evtId = evt.getId();
  
  // Create public field booking  
  if(booking.isFieldBooking) {
    // Create field booking event
    title = "Provisional field booking";
    
    // Get calendar and create event
    var cal = CalendarApp.getCalendarsByName(CAL_NAME_FIELD)[0];
    var fEvt = cal.createEvent(title, startTime, endTime, options);
  
    // Set up event
    configureCalendarEvent_(fEvt, booking);
    fEvt.setTag("LinkedBooking", evtId);
    
    // Save event Id in details booking
    evt.setTag("FieldEventId", fEvt.getId());
  }
  
  // Create public house booking
  if(booking.isHouseBooking) {
    // Create house booking event
    title = "Provisional house booking";
    
    // Get calendar and create event
    var cal = CalendarApp.getCalendarsByName(CAL_NAME_HOUSE)[0];
    var hEvt = cal.createEvent(title, startTime, endTime, options);
  
    // Set up event
    configureCalendarEvent_(hEvt, booking);
    hEvt.setTag("LinkedBooking", evtId);
    
    // Save event Id in details booking
    evt.setTag("HouseEventId", hEvt.getId());
  }
  
  return evtId;
}

/**
 * Confirms the selected event.
 */
function confirmEvent_(booking) {
  var evtId = booking.docs.eventID;
  var evt = CalendarApp.getEventSeriesById(evtId);
  
  if(evt == null) {
    Logger.log("Could not find calendar event for %s [%s]", booking.eventName, evtId);
    return;
  }
  var title = "[C] " + booking.organisation.name + " (" + booking.participants + " participants, " + booking.leaders + " leaders)\n" + booking.contact.name + " - " + booking.contact.telephone + "";
  evt.setTitle(title);
  evt.setTag("BookingState", "Confirmed");
  
  var fEvtId = evt.getTag("FieldEventId");
  Logger.log("Confirm associated field event:" + fEvtId);
  if(fEvtId != null) {
    var fEvt = CalendarApp.getCalendarsByName(CAL_NAME_FIELD)[0].getEventSeriesById(fEvtId);
    if(fEvt == null) {
      Logger.log("Could not find field calendar event for %s [%s]", booking.eventName, fEvtId);
    } else {
      fEvt.setTitle(booking.eventType);
      fEvt.setTag("BookingState", "Confirmed");
    }
  }
  
  var hEvtId = evt.getTag("HouseEventId");
  Logger.log("Confirm associated house event:" + hEvtId);
  if(hEvtId != null) {
    var hEvt = CalendarApp.getCalendarsByName(CAL_NAME_HOUSE)[0].getEventSeriesById(hEvtId);
    if(hEvt == null) {
      Logger.log("Could not find house calendar event for %s [%s]", booking.eventName, hEvtId);
    } else {
      hEvt.setTitle(booking.eventType);
      hEvt.setTag("BookingState", "Confirmed");
    }
  }
}

/**
 * Deletes the selected event.
 */
function deleteEvent_(booking) {
  var evtId = booking.docs.eventID;
  var evt = CalendarApp.getEventSeriesById(evtId);
  
  if(evt == null) {
    Logger.log("Could not find calendar event for %s [%s]", booking.eventName, booking.docs.eventID);
    return;
  }
  evt.deleteEventSeries();
  
  var fEvtId = evt.getTag("FieldBookingId");
  if(fEvtId != null) {
    var fEvt = CalendarApp.getCalendarsByName(CAL_NAME_FIELD)[0].getEventSeriesById(fEvtId);
    if(fEvt == null) {
      Logger.log("Could not find field calendar event for %s [%s]", booking.eventName, fEvtId);
    } else {
      fEvt.deleteEventSeries();
    }
  }
  
  var hEvtId = evt.getTag("HouseBookingId");
  if(hEvtId != null) {
    var hEvt = CalendarApp.getCalendarsByName(CAL_NAME_HOUSE)[0].getEventSeriesById(hEvtId);
    if(hEvt == null) {
      Logger.log("Could not find house calendar event for %s [%s]", booking.eventName, hEvtId);
    } else {
      hEvt.deleteEventSeries();
    }
  }
}

/**
 * Checks if the requested booking slot is available in the calendar.
 * @return if the booking slot is free.
 */
function isBookingAvailable_(booking) {
  var errs = [];
  var warns = [];
  
  return isBookingAvailable_(booking, errs, warns);
}

/**
 * Checks if the requested booking slot is available in the calendar. Adds error and
 * warning messages to supplied arrays.
 * @return if the booking slot is free.
 */
function isBookingAvailable_(booking, errs, warns) {
  
  if(errs == null) {
    errs = [];
  }
  if(warns == null) {
    warns = [];
  }
  
  if(booking.isHouseBooking) {
    // Check house bookings
    var cal = CalendarApp.getCalendarsByName(CAL_NAME_HOUSE)[0];
    var evts = cal.getEvents(booking.arrivalDate, booking.departureDate);
    // For the house, only one booking can exist at one time
    if(evts.length >= 1) {
      errs.push("Conflict with existing house booking " + evts[0].getTitle() + (evts[0].getGuestList().length > 0 ? " (by " + evts[0].getGuestList()[0].getEmail() + ")" : "") + " at " + evts[0].getStartTime() + " - " + evts[0].getEndTime());
    }
  }
  
  if(booking.isFieldBooking) {
    // Check field bookings
    var cal = CalendarApp.getCalendarsByName(CAL_NAME_FIELD)[0];
    var evts = cal.getEvents(booking.arrivalDate, booking.departureDate);
    // For the field, two groups of <= 30 participants can co-exist, but never more than 2 groups
    for(i = 0; i < evts.length; i ++) {
      if((booking.participants + booking.leaders) > 30 || evts[0].getTag("HeadCount") > 30 || evts.length >= 2) {
        errs.push("Conflict with existing field booking by " + evts[0].getTitle() + " (" + evts[0].getGuestList()[0].getEmail() + ") for " + evts[0].getStartTime() + " - " + evts[0].getEndTime());
      }
      else if(booking.organisation.type == ORG_TYPE_YOUTH) {
        // Not a GG group making field booking, should be checked with other bookers
        warns.push("Non-Guide organisation booking request overlaps with existing field booking by " + evts[0].getTitle() + "\n");
      }
    }
  }
    
  return (errs.length == 0);
}
